﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Linq;

namespace WordCloudHelper
{
    
    public class WordCloud
    {
        
        public WordCloud(int width, int height, bool useRank = false, Color? fontColor = null, int maxFontSize = -1, int fontStep = 1)
        {
            this.Map = new OccupancyMap(width, height);
            this.Image = new FastImage(width, height, PixelFormat.Format32bppArgb);
            this.MaxFontSize = ((maxFontSize < 0) ? height : maxFontSize);
            this.FontStep = fontStep;
            this.m_fontColor = fontColor;
            this.UseRank = useRank;
            this.Random = new Random();
        }

        
        public Image Draw(List<string> words, List<int> freqs)
        {
            int num = this.MaxFontSize;
            if (words == null || freqs == null)
            {
                throw new ArgumentException("Arguments null.");
            }
            if (words.Count != freqs.Count)
            {
                throw new ArgumentException("Must have the same number of words as frequencies.");
            }
            using (Graphics graphics = Graphics.FromImage(this.Image.Bitmap))
            {
                graphics.Clear(Color.Transparent);
                graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
                for (int i = 0; i < words.Count; i++)
                {
                    if (!this.UseRank)
                    {
                        num = (int)Math.Min((double)num, 100.0 * Math.Log10((double)(freqs[i] + 100)));
                    }
                    StringFormat genericTypographic = StringFormat.GenericTypographic;
                    genericTypographic.FormatFlags &= ~StringFormatFlags.LineLimit;
                    Font font;
                    int num2;
                    int num3;
                    bool flag;
                    do
                    {
                        font = new Font(FontFamily.GenericSansSerif, (float)num, GraphicsUnit.Pixel);
                        SizeF sizeF = graphics.MeasureString(words[i], font, new PointF(0f, 0f), genericTypographic);
                        flag = this.Map.TryFindUnoccupiedPosition((int)sizeF.Width, (int)sizeF.Height, out num2, out num3);
                        if (!flag)
                        {
                            num -= this.FontStep;
                        }
                    }
                    while (num > 0 && !flag);
                    if (num <= 0)
                    {
                        break;
                    }
                    graphics.DrawString(words[i], font, new SolidBrush(this.FontColor), (float)num2, (float)num3, genericTypographic);
                    this.Map.Update(this.Image, num2, num3);
                }
            }
            object obj = this.Image.Bitmap.Clone();
            this.Image.Dispose();
            return (Image)obj;
        }


        public Image Draw(List<string> words)
        {
            List<int> freqs = null;
           
            var result = words.GroupBy(s => s).Select(s => new {
                word=s.Key,
                num=s.Count()
            }).OrderByDescending(s=>s.num);
            words = result.Select(s => s.word).ToList();
            freqs = result.Select(s => s.num).ToList();

            return Draw(words, freqs);
        }

       
        private Color FontColor
        {
            get
            {
                Color? fontColor = this.m_fontColor;
                if (fontColor == null)
                {
                    return this.GetRandomColor();
                }
                return fontColor.GetValueOrDefault();
            }
            set
            {
                this.m_fontColor = new Color?(value);
            }
        }

     
        private Color GetRandomColor()
        {
            return Color.FromArgb(this.Random.Next(0, 255), this.Random.Next(0, 255), this.Random.Next(0, 255));
        }

       
        private Random Random { get; set; }

       
        private FastImage Image { get; set; }

       
        private OccupancyMap Map { get; set; }

       
        private int MaxFontSize { get; set; }

       
        private bool UseRank { get; set; }

       
        private int FontStep { get; set; }

      
        private Color? m_fontColor;
    }
}
